package com.atwisdom.star.core.bsl.modelClass.tank.Impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.actionType.modelClass.tank.TankActionType;
import com.atwisdom.star.common.vo.*;
import com.atwisdom.star.core.bsl.modelClass.tank.TankModelBslService;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierModel;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierPropertiesUtils;
import com.atwisdom.star.core.dao.pojo.modelClass.tank.TankInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.tank.TankModel;
import com.atwisdom.star.core.dsl.modelClass.consume.Impl.ConsumeInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.hier.Impl.HierInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.hier.Impl.HierModelDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.resource.Impl.ResourceInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.tank.Impl.TankInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.tank.Impl.TankModelDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.utils.QueryBuilder;
import com.atwisdom.star.exception.pojo.BusinessException;
import org.apache.commons.lang.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.List;

@Service
public class TankModelBslServiceImpl implements TankModelBslService {
    private TankModelDslServiceImpl tankModelDslService;
    private TankInstanceDslServiceImpl tankInstanceDslService;
    private ConsumeInstanceDslServiceImpl consumeInstanceDslService ;
    private ResourceInstanceDslServiceImpl resourceInstanceDslService;
    private LogicInstanceDslServiceImpl logicInstanceDslService;
    private HierInstanceDslServiceImpl hierInstanceDslService;
    private HierModelDslServiceImpl hierModelDslService;
    private QueryBuilder queryBuilder;
    @Autowired
    public void setTankModelDslService(TankModelDslServiceImpl tankModelDslService) {
        this.tankModelDslService = tankModelDslService;
    }
    @Autowired
    public void setLogicInstanceDslService(LogicInstanceDslServiceImpl logicInstanceDslService) {
        this.logicInstanceDslService = logicInstanceDslService;
    }

    @Autowired
    public void setHierInstanceDslService(HierInstanceDslServiceImpl hierInstanceDslService) {
        this.hierInstanceDslService = hierInstanceDslService;
    }
    @Autowired
    public void setHierModelDslService(HierModelDslServiceImpl hierModelDslService) {
        this.hierModelDslService = hierModelDslService;
    }
    @Autowired
    public void setQueryBuilder(QueryBuilder queryBuilder) {
        this.queryBuilder = queryBuilder;
    }

    @Autowired
    public void setConsumeInstanceDslService(ConsumeInstanceDslServiceImpl consumeInstanceDslService) {
        this.consumeInstanceDslService = consumeInstanceDslService;
    }
    @Autowired
    public void setResourceInstanceDslService(ResourceInstanceDslServiceImpl resourceInstanceDslService) {
        this.resourceInstanceDslService = resourceInstanceDslService;
    }
    @Autowired
    public void setTankInstanceDslService(TankInstanceDslServiceImpl tankInstanceDslService) {
        this.tankInstanceDslService = tankInstanceDslService;
    }

    /**
     * 服务工厂方法
     * @param actionDataList 参数
     * @return 参数
     * @throws BusinessException 异常
     */
    @Transactional
    public ResultInfo<?> responseFactory(List<ActionData<JSONObject>> actionDataList) throws BusinessException {
        ResultInfo<?> resultInfo = null;
        for (ActionData<JSONObject> actionData : actionDataList) {
            String action = actionData.getAction();
            TankActionType actionType = TankActionType.valueOf(action);
            String methodName = actionType.getMethodName();
            resultInfo = this.execMethod(methodName, actionData);
        }
        return resultInfo;
    }

    /**
     * 反射执行业务单元方法
     *
     * @param methodName 方法名
     * @param actionData 方法参数
     * @return 返回结果
     * @throws BusinessException 业务异常
     */
    public ResultInfo<?> execMethod(String methodName, ActionData<JSONObject> actionData) throws BusinessException {
        Class<? extends TankModelBslServiceImpl> clz = this.getClass();
        try {
            Method method = clz.getMethod(methodName, ActionData.class);
            TankModelBslServiceImpl service = (TankModelBslServiceImpl) AopContext.currentProxy();
            return (ResultInfo<?>) method.invoke(service, actionData);
        } catch (NoSuchMethodException ex) {
            throw new BusinessException("999999", "没有找到该方法(" + methodName + ")", ex);
        } catch (IllegalAccessException ex) {
            throw new BusinessException("999999", "没有访问该方法权限(" + methodName + ")", ex);
        } catch (InvocationTargetException ex) {
            Throwable targetException = ex.getTargetException();
            if (targetException instanceof BusinessException) {
                BusinessException bex = (BusinessException) targetException;
                throw new BusinessException("999999", bex.getErrorMsg(), ex);
            } else {
                throw new BusinessException("999999", "出错了请重试：(" + methodName + ")---" + ex.getMessage(), ex);
            }
        }
    }

    /**
     * 查询全部摘要（通用）
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> queryAllInfo(ActionData<JSONObject> actionData) {
        List<JSONObject> jsonObjectList = this.tankModelDslService.queryAllInfo();
        return JsonResult.success(jsonObjectList);
    }

    /**
     * 分页查询全部摘要（通用）
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<PageInfo> queryAllInfoByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.queryAllInfoByPage(pageNumber, pageSize, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     * 查询全部数据（通用）
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> queryAll(ActionData<JSONObject> actionData) {
        List<JSONObject> jsonObjectList = this.tankModelDslService.queryAll();
        return JsonResult.success(jsonObjectList);
    }

    /**
     * 分页查询全部数据（通用）
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> listAllByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.listAllByPage(pageNumber, pageSize, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     * 按条件查询模型
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> query(ActionData<JSONObject> actionData) {
        String condition = actionData.getCondition();
        String className = actionData.getClassName();
        String orderBy = actionData.getOrderBy();
        List<JSONObject> query = this.tankModelDslService.query(condition, className, orderBy);
        return JsonResult.success(query);
    }


    /**
     * 根据类名查询容器属性
     * @param actionData 类名
     * @return 返回结果
     * @throws BusinessException 异常
     */
    public ResultInfo<?> queryHierProperties(ActionData<JSONObject> actionData){
        String className = actionData.getClassName();
        List<HierModel> hierModels = this.hierModelDslService.queryByClassName(ModelType.Tank.getCode(), className);
        HierPropertiesUtils hierPropertiesUtils = new HierPropertiesUtils(hierModels);
        JSONObject jsonObject = hierPropertiesUtils.fetchHierProperties();
        return JsonResult.success(jsonObject);
    }

    /**
     * 按条件分页查询模型摘要
     * @param actionData 参数，包括：
     *  1、pageNumber 第几页
     *  2、pageSize 每页多少条
     *  3、condition 查询条件，拼在where 后面
     *  4、className 模型类名，可以直接传入也可在condition传入
     *  5、orderBy 排序 ：“id,asc;className,updateTime,desc”
     * @return 返回结果
     */
    public ResultInfo<?> queryInfoByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String condition = actionData.getCondition();
        String className = actionData.getClassName();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.queryInfoByPage(pageNumber, pageSize, condition, className, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     * 按条件分页查询模型
     * @param actionData 参数，包括：
     *  1、pageNumber 第几页
     *  2、pageSize 每页多少条
     *  3、condition 查询条件，拼在where 后面
     *  4、className 模型类名，可以直接传入也可在condition传入
     *  5、orderBy 排序 ：“id,asc;className,updateTime,desc”
     * @return 返回结果
     */
    public ResultInfo<?> queryByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String condition = actionData.getCondition();
        String className = actionData.getClassName();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.queryByPage(pageNumber, pageSize, condition, className, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     * 分页查询全部版本摘要（通用），包括：
     *  1、pageNumber 第几页
     *  2、pageSize 每页多少条
     *  3、orderBy 排序 ：“id,asc;className,updateTime,desc”
     * @return 返回结果
     */
    @Override
    public ResultInfo<?> queryAllVersionInfoByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.queryAllVersionInfoByPage(pageNumber, pageSize, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     * 分页条件查询版本摘要（通用），包括：
     *  1、pageNumber 第几页
     *  2、pageSize 每页多少条
     *  3、condition 查询条件，拼在where 后面
     *  4、className 模型类名，可以直接传入也可在condition传入
     *  5、orderBy 排序 ：“id,asc;className,updateTime,desc”
     * @return 返回结果
     */
    public ResultInfo<?> queryVersionInfoByPage(ActionData<JSONObject> actionData) {
        int pageNumber = actionData.getPageNumber();
        int pageSize = actionData.getPageSize();
        String condition = actionData.getCondition();
        String className = actionData.getClassName();
        String orderBy = actionData.getOrderBy();
        PageInfo pageInfo = this.tankModelDslService.queryVersionInfoByPage(pageNumber, pageSize, condition, className, orderBy);
        return JsonResult.success(pageInfo);
    }

    /**
     *按条件和版本查询（通用）
     * @param actionData 参数，包括：
     *  1、condition 查询条件，拼在where 后面
     *  2、className 模型类名，可以直接传入也可在condition传入
     *  3、version 模型版本号
     *  4、orderBy 排序 ：“id,asc;className,updateTime,desc”
     * @return 返回值
     */
    @Override
    public ResultInfo<?> queryVersion(ActionData<JSONObject> actionData) {
        String condition = actionData.getCondition();
        String className = actionData.getClassName();
        BigDecimal version = actionData.getVersion();
        String orderBy = actionData.getOrderBy();
        List<JSONObject> jsonObjectList = this.tankModelDslService.queryVersion(condition, className, version, orderBy);
        return JsonResult.success(jsonObjectList);
    }

    /**
     * 设置版本有效
     *
     * @param actionData 参数，包括：
     * 1、className 模型类名，可以直接传入也可在condition传入
     * 2、version 模型版本号
     * @return 返回值
     */
    @Override
    public ResultInfo<?> setPublish(ActionData<JSONObject> actionData) {
        String className = actionData.getClassName();
        BigDecimal version = actionData.getVersion();
        this.tankModelDslService.setPublish(className, version);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 设置版本无效
     *
     * @param actionData 参数，包括：
     * 1、className 模型类名，可以直接传入也可在condition传入
     * @return 返回值
     */
    @Override
    public ResultInfo<?> setUnPublish(ActionData<JSONObject> actionData) {
        String className = actionData.getClassName();
        this.tankModelDslService.setUnPublish(className);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 版本升级
     *
     * @param actionData 参数，包括：
     * 1、className 模型类名，可以直接传入也可在condition传入
     *
     * @return 返回值
     */
    @Override
    public ResultInfo<?> upgrade(ActionData<JSONObject> actionData) {
        String className = actionData.getClassName();
        this.tankModelDslService.upgrade(className);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 添加新模型
     *
     * @param actionData 参数，包括：
     * 1、从 actionData.data中取第一个对象数据
     * 2、解析出type 模型类型
     * 3、className 模型类名
     * @return 返回值
     */
    @Override
    public ResultInfo<?> add(ActionData<JSONObject> actionData) {
        List<JSONObject> data = actionData.getData();
        JSONObject jsonObject = data.get(0);
        String type = jsonObject.getString("type");
        String className = jsonObject.getString("className");
        JSONObject addJsonObject = this.tankModelDslService.add(type, className);
        return JsonResult.success(addJsonObject);
    }

    /**
     * 拷贝模型
     *
     * @param actionData 参数，包括：
     * 1、type 新模型类型
     * 2、className 新模型类名
     * 3、oldType 原模型类型
     * 4、oldClassName 原模型类名
     *
     * @return 返回值
     */
    @Override
    public ResultInfo<?> clone(ActionData<JSONObject> actionData) {
        String type = actionData.getType();
        String className = actionData.getClassName();
        String oldType = actionData.getOldType();
        String oldClassName = actionData.getOldClassName();
        JSONObject clone = this.tankModelDslService.clone(type, className, oldType, oldClassName);
        return JsonResult.success(clone);
    }

    /**
     * 更新模型类型和类名（配置阶段），包括：
     *
     * @param actionData 参数，包括：
     * 1、type 更新模型类型
     * 2、className 更新模型类名
     * 3、oldType 原模型类型
     * 4、oldClassName 原模型类名
     * @return 返回值
     */
    @Override
    public ResultInfo<?> updateClassName(ActionData<JSONObject> actionData) {
        String type = actionData.getType();
        String className = actionData.getClassName();
        String oldType = actionData.getOldType();
        String oldClassName = actionData.getOldClassName();
        JSONObject jsonObject = this.tankModelDslService.updateClassName(type, className, oldType, oldClassName);
        return JsonResult.success(jsonObject);
    }

    /**
     * 更新模型属性字段
     *
     * @param actionData 参数，包括：
     * 更新，需要同步更新实例，同步更新历史数据
     * 1、jsonObject 更新模型数据
     * @return 返回值
     */
    @Override
    public ResultInfo<?> updateById(ActionData<JSONObject> actionData) {
        List<JSONObject> data = actionData.getData();
        JSONObject jsonObject = data.get(0);
        return JsonResult.success(this.tankModelDslService.updateById(jsonObject));
    }

    /**
     * 更新容器属性
     * @param actionData 更新参数，包括：
     * 1、验证要更新模型是否存在，不存返回模型不能存在
     * 2、获取已经利用该模型创建的实例
     * 3、根据新的容器属性循环更新每个实例
     * 4、初化需要根据容器linkType、linkClassName创建
     * @return 返回更新后模型
     */
    public ResultInfo<?> updateHierProperties(ActionData<JSONObject> actionData){
        List<JSONObject> data = actionData.getData();
        JSONObject jsonObject = data.get(0);
        String className = jsonObject.getString("className");
        JSONObject hierProperties = jsonObject.getJSONObject("hierProperties");
        JSONObject web = jsonObject.getJSONObject("web");
        JSONObject others = jsonObject.getJSONObject("others");
        TankModel tankModel = this.tankModelDslService.queryByClassName(className);
        if(tankModel==null){
            return JsonResult.error(StatusCode.ERROR_MODEL_NOT_EXIST);
        }
        List<TankInstance> tankInstances = this.tankInstanceDslService.queryByClassName(className);
        List<HierModel> hierModelList = hierModelDslService.queryByClassName(ModelType.Tank.getCode(), className);
        tankInstances.forEach(ins->{
            List<HierInstance> hierInstances = hierInstanceDslService.queryByContainerId(ModelType.Tank.getCode(), className, ins.getId());
            ins.setHierModels(hierModelList);
            ins.setHierInstances(hierInstances);
            ins.setWeb(web);
            ins.setOthers(others);
            JSONObject hier = ins.getHier();
            JSONObject hierJson = queryBuilder.fetchHierBy(hierProperties, hier);
            //处理hier link 实例创建
            this.dealHierLinkInstance(hierJson);
            // this.hierInstanceDslService.updateByContainerId(ModelType.Tank.getCode(), className, ins.getId(), hierJson);
            this.tankInstanceDslService.updateById(ins);
        });

        hierProperties.put("model",ModelType.Tank.getCode());
        hierProperties.put("className",className);
        JSONObject modelJsonObject = this.tankModelDslService.updateHierProperties(className, web, others, hierProperties);
        return JsonResult.success(modelJsonObject);
    }

    /**
     * 处理hierLink
     * @param hier 参数
     */
    private void dealHierLinkInstance(JSONObject hier){
        JSONArray tempContent = hier.getJSONArray("content");
        JSONArray content = new JSONArray();
        for (int i = 0; i < tempContent.size(); i++) {
            JSONObject contentJson = tempContent.getJSONObject(i);
            JSONObject link = contentJson.getJSONObject("link");
            this.createInstance(link);
            contentJson.put("link",link);
            content.add(contentJson);
        }
        hier.put("content",content);
    }

    /**
     * 根据link 创建实例
     * @param link 创建实例参数
     */
    private void createInstance(JSONObject link){
        if (link == null) {
            return;
        }
        String id = link.getString("id");
        if (StringUtils.isNotBlank(id)) {
            return;
        }

        String linkType = link.getString("linkType");
        String linkModel = link.getString("linkModel");
        String linkClassName = link.getString("linkClassName");
        if (StringUtils.isBlank(linkType) || StringUtils.isBlank(linkClassName) || StringUtils.isBlank(linkModel)) {
            return;
        }

        ModelType modelType = ModelType.getByCode(linkModel);
        JSONObject jsonObject;
        switch (modelType){
            case Consume:
                jsonObject = consumeInstanceDslService.add(linkType, linkClassName, linkClassName,null);
                link.put("linkId",jsonObject.getString("id"));
                break;
            case Resource:
                jsonObject = resourceInstanceDslService.add(linkType, linkClassName, linkClassName,null);
                link.put("linkId",jsonObject.getString("id"));
                break;
            case Logic:
                jsonObject= logicInstanceDslService.add(linkType, linkClassName, linkClassName,null);
                link.put("linkId",jsonObject.getString("id"));
                break;
            case Tank:
                jsonObject = tankInstanceDslService.add(linkType, linkClassName, linkClassName,null);
                link.put("linkId",jsonObject.getString("id"));
                break;
            default:
                break;
        }
    }

    /**
     * 按ids删除模型
     *
     * @param actionData 参数，包括：
     * 1、ids,要删除模型的主键标识
     * 2、删除模型前先把模型对应的容器hierModel先删除
     * 3、按ids删除模型
     *
     * @return 返回值
     */
    @Override
    public ResultInfo<?> deleteByIds(ActionData<JSONObject> actionData) {
        List<Long> ids = actionData.getIds();
        this.tankModelDslService.deleteByIds(ids);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 接className删除
     * 1、删除实例、2、删除历史 3、更新redis
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> deleteByClassName(ActionData<JSONObject> actionData) {
        String className = actionData.getClassName();
        this.tankModelDslService.deleteByClassName(className);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 批量删除
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> deleteByClassNames(ActionData<JSONObject> actionData) {
        List<String> classNames = actionData.getClassNames();
        this.tankModelDslService.deleteByClassNames(classNames);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 按Id 废除模型
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> repealByIds(ActionData<JSONObject> actionData) {
        List<Long> ids = actionData.getIds();
        this.tankModelDslService.repealByIds(ids);
        return JsonResult.success(StatusCode.SUCCESS);
    }

    /**
     * 批量废除
     *
     * @param actionData 参数
     * @return 返回值
     */
    @Override
    public ResultInfo<?> repealByClassNames(ActionData<JSONObject> actionData) {
        List<String> classNames = actionData.getClassNames();
        this.tankModelDslService.repealByClassNames(classNames);
        return JsonResult.success(StatusCode.SUCCESS);
    }
}
